package main

import (
	"html/template"
	"net/http"
	"path/filepath"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// 模板缓存，结构为：主题名 -> (页面名 -> 模板对象)
var (
	templateCache = map[string]map[string]*template.Template{} // theme -> (page -> template)
	cfg           Config                                       // 全局配置对象
)

// 初始化模板缓存（支持多主题）
// 该函数会遍历 templates 目录下的所有主题，每个主题下的页面、布局和局部模板文件，
// 并将解析后的模板对象缓存到内存中，便于后续渲染时快速获取。
func initTemplateCache() map[string]map[string]*template.Template {
	cache := make(map[string]map[string]*template.Template)

	// 获取所有主题目录
	themes, err := filepath.Glob("templates/*")
	if err != nil {
		panic(err)
	}

	// 定义模板函数，可在模板中调用
	funcMap := template.FuncMap{
		"formatDate": func(t time.Time) string {
			return t.Format("2006-01-02 15:04:05") // 格式化时间
		},
		"upper": strings.ToUpper, // 字符串转大写
	}

	for _, themeDir := range themes {
		themeName := filepath.Base(themeDir)
		cache[themeName] = make(map[string]*template.Template)

		// 获取页面、布局、局部模板文件列表
		pages, _ := filepath.Glob(filepath.Join(themeDir, "pages", "*.html"))
		layouts, _ := filepath.Glob(filepath.Join(themeDir, "layouts", "*.html"))
		partials, _ := filepath.Glob(filepath.Join(themeDir, "partials", "*.html"))

		for _, page := range pages {
			// 合并布局、局部和页面文件，解析为一个模板
			files := append(layouts, append(partials, page)...)
			name := filepath.Base(page)
			tmpl := template.Must(template.New(name).Funcs(funcMap).ParseFiles(files...))
			cache[themeName][name] = tmpl
		}
	}

	return cache
}

// 渲染函数
// 根据请求参数选择主题，渲染指定页面。
// 开发模式下每次请求重新解析模板，生产模式下使用缓存。
func render(c *gin.Context, page string, data any) {
	// 获取主题参数，默认为配置中的主题
	theme := c.Query("theme")
	if theme == "" {
		theme = cfg.DefaultTheme
	}

	var tmpl *template.Template
	var err error

	// 开发模式：每次请求重新解析模板，便于调试
	if cfg.Env == "dev" {
		cache := initTemplateCache()
		tmpl = cache[theme][page]
	} else {
		// 生产模式：使用初始化时的缓存，提升性能
		tmpl = templateCache[theme][page]
	}

	if tmpl == nil {
		c.String(http.StatusNotFound, "Template not found for theme '%s': %s", theme, page)
		return
	}

	c.Header("Content-Type", "text/html; charset=utf-8")
	err = tmpl.ExecuteTemplate(c.Writer, "layout", data)
	if err != nil {
		c.String(http.StatusInternalServerError, err.Error())
	}
}

// 程序入口
func main() {
	cfg = LoadConfig() // 加载配置
	r := gin.Default() // 创建 Gin 路由引擎

	// 生产模式初始化模板缓存，开发模式每次请求动态解析
	if cfg.Env == "prod" {
		templateCache = initTemplateCache()
	}

	// 静态资源路由
	r.Static("/static", "./static")

	// 首页路由
	r.GET("/", func(c *gin.Context) {
		data := gin.H{
			"User": "Alice",    // 示例用户
			"Date": time.Now(), // 当前时间
		}
		render(c, "index.html", data)
	})

	// 关于页路由
	r.GET("/about", func(c *gin.Context) {
		data := gin.H{
			"Author": "Gopher",   // 作者
			"Now":    time.Now(), // 当前时间
		}
		render(c, "about.html", data)
	})

	// 启动服务，监听 8080 端口
	r.Run(":8080")
}
